package com.leiqichao.backend.interceptor;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.leiqichao.backend.service.StatVisitService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Arrays;
import java.util.List;

/**
 * 一个Spring MVC拦截器，用于统计访问信息。
 * 该拦截器会在每个请求到达控制器之前记录访问者的IP地址、请求路径、来源页面和用户代理信息。
 */
@Component
public class StatsInterceptor implements HandlerInterceptor {

    /**
     * 需要排除统计的路径列表。
     * 这些路径下的请求不会被记录。
     */
    private static final List<String> EXCLUDE_PATHS = Arrays.asList(
            "/api/stats",       // 统计接口
            "/actuator/health", // 健康检查接口
            "/v3/api-docs"      // API文档接口
    );

    /**
     * 自动注入的StatVisitService实例，用于记录访问信息。
     */
    @Autowired
    private StatVisitService statVisitService;

    /**
     * 在请求处理之前被调用。
     * 用于记录访问信息。
     *
     * @param request  当前HTTP请求对象
     * @param response 当前HTTP响应对象
     * @param handler  处理请求的目标处理器
     * @return 如果返回true，则继续处理请求；如果返回false，则中断请求处理
     */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws JsonProcessingException {
        // 获取请求路径
        String path = request.getRequestURI();

        // 如果请求路径在排除列表中，则不记录访问信息，直接返回true
        if (EXCLUDE_PATHS.stream().anyMatch(path::startsWith)) {
            return true;
        }

        // 获取客户端IP地址
        String ip = getClientIp(request);
        // 获取来源页面URL
        String referrer = request.getHeader("Referer");
        // 获取用户代理信息
        String userAgent = request.getHeader("User-Agent");

        // 记录访问信息
        statVisitService.recordVisit(ip, path, referrer, userAgent);

        // 继续处理请求
        return true;
    }

    /**
     * 获取客户端的真实IP地址。
     * 尝试从多个请求头中获取IP地址，以支持代理服务器。
     *
     * @param request 当前HTTP请求对象
     * @return 客户端的真实IP地址
     */
    public String getClientIp(HttpServletRequest request) {
        // 尝试从X-Forwarded-For头中获取IP地址
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            // 如果X-Forwarded-For头不存在或无效，则尝试从Proxy-Client-IP头中获取IP地址
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            // 如果Proxy-Client-IP头不存在或无效，则尝试从WL-Proxy-Client-IP头中获取IP地址
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            // 如果所有代理头都不存在或无效，则使用远程地址作为IP地址
            ip = request.getRemoteAddr();
        }
        // 如果IP地址包含多个值（例如通过多个代理服务器传递），则取第一个值
        return ip.split(",")[0];
    }
}
